﻿using Abp.Application.Services.Dto;
using Abp.Domain.Entities;
using Abp.Domain.Repositories;
using AbpProjectTemplate.Application.Dtos;
using System.Linq;
using System.Threading.Tasks;

namespace AbpProjectTemplate.Application
{
    public abstract class MultiLingualCrudApplicationService<TEntity, TEntityTranslation, TPrimaryKey, TEntityDto, TEntityListItem, TGetPagedListInput, TCreateInput, TUpdateInput, TTranslationDto, TGetInput, TDeleteInput>
      : AsyncCrudApplicationService<TEntity, TPrimaryKey, TEntityDto, TEntityListItem, TGetPagedListInput, TCreateInput, TUpdateInput, TGetInput, TDeleteInput>
      where TEntity : class, IEntity<TPrimaryKey>, IMultiLingualEntity<TEntityTranslation>
      where TEntityTranslation : class, IEntity<int>, IEntityTranslation<TEntity>
      where TEntityDto : IEntityDto<TPrimaryKey>
      where TEntityListItem : IEntityDto<TPrimaryKey>
      where TUpdateInput : IEntityDto<TPrimaryKey>
      where TTranslationDto : TranslationDto
      where TGetInput : EntityDto<TPrimaryKey>
      where TDeleteInput : EntityDto<TPrimaryKey>
    {
        protected readonly IRepository<TEntityTranslation> TranslationRepository;

        public MultiLingualCrudApplicationService(IRepository<TEntity, TPrimaryKey> repository, 
            IRepository<TEntityTranslation> translationRepository,
            string managerPermisson = null)
            : base(repository, managerPermisson)
        {
            this.TranslationRepository = translationRepository;
        }

        protected override Task<TEntity> GetEntityByIdAsync(TPrimaryKey id)
        {
            this.CheckGetPermission();

            return this.AsyncQueryableExecuter.FirstOrDefaultAsync(this.Repository.GetAllIncluding(t => t.Translations).Where(t => t.Id.Equals(id)));
        }

        public async Task Translate(TTranslationDto input)
        {
            this.CheckUpdatePermission();

            var query = this.TranslationRepository.GetAll().Where(t => t.CoreId == input.CoreId);

            var translation = await this.AsyncQueryableExecuter.FirstOrDefaultAsync(query);

            if (translation == null)
            {
                var newTranslation = this.ObjectMapper.Map<TEntityTranslation>(input);
                await this.TranslationRepository.InsertAsync(newTranslation);
            }
            else
            {
                this.ObjectMapper.Map(input, translation);
            }
        }

        protected override IQueryable<TEntity> CreateFilteredQuery(TGetPagedListInput input)
        {
            return this.Repository.GetAllIncluding(t => t.Translations);
        }
    }

    public class MultiLingualCrudApplicationService<TEntity, TEntityTranslation, TPrimaryKey, TEntityDto, TEntityListItem, TGetPagedListInput, TCreateInput, TUpdateInput, TTranslationDto>
      : MultiLingualCrudApplicationService<TEntity, TEntityTranslation, TPrimaryKey, TEntityDto, TEntityListItem, TGetPagedListInput, TCreateInput, TUpdateInput, TTranslationDto, EntityDto<TPrimaryKey>, EntityDto<TPrimaryKey>>
      where TEntity : class, IEntity<TPrimaryKey>, IMultiLingualEntity<TEntityTranslation>
      where TEntityTranslation : class, IEntity<int>, IEntityTranslation<TEntity>
      where TEntityDto : IEntityDto<TPrimaryKey>
      where TEntityListItem : IEntityDto<TPrimaryKey>
      where TUpdateInput : IEntityDto<TPrimaryKey>
      where TTranslationDto : TranslationDto
    {
        public MultiLingualCrudApplicationService(IRepository<TEntity, TPrimaryKey> repository
            , IRepository<TEntityTranslation> translationRepository
            ,string managerPermisson = null) : base(repository, translationRepository, managerPermisson) { }
    }

    public class MultiLingualCrudApplicationService<TEntity, TEntityTranslation, TPrimaryKey, TEntityDto, TEntityListItem, TGetPagedListInput, TEditDto, TTranslationDto>
      : MultiLingualCrudApplicationService<TEntity, TEntityTranslation, TPrimaryKey, TEntityDto, TEntityListItem, TGetPagedListInput, TEditDto, TEditDto, TTranslationDto, EntityDto<TPrimaryKey>, EntityDto<TPrimaryKey>>
      where TEntity : class, IEntity<TPrimaryKey>, IMultiLingualEntity<TEntityTranslation>
      where TEntityTranslation : class, IEntity<int>, IEntityTranslation<TEntity>
      where TEntityDto : IEntityDto<TPrimaryKey>
      where TEntityListItem : IEntityDto<TPrimaryKey>
      where TEditDto : IEntityDto<TPrimaryKey>
      where TTranslationDto : TranslationDto
    {
        public MultiLingualCrudApplicationService(IRepository<TEntity, TPrimaryKey> repository
            , IRepository<TEntityTranslation> translationRepository
            , string managerPermisson = null) : base(repository, translationRepository, managerPermisson) { }
    }

    public class MultiLingualCrudApplicationService<TEntity, TEntityTranslation, TEntityDto, TEntityListItem, TGetPagedListInput, TEditDto, TTranslationDto>
       : MultiLingualCrudApplicationService<TEntity, TEntityTranslation, int, TEntityDto, TEntityListItem, TGetPagedListInput, TEditDto, TEditDto, TTranslationDto, EntityDto<int>, EntityDto<int>>
       where TEntity : class, IEntity<int>, IMultiLingualEntity<TEntityTranslation>
       where TEntityTranslation : class, IEntity<int>, IEntityTranslation<TEntity>
       where TEntityDto : IEntityDto<int>
       where TEntityListItem : IEntityDto<int>
       where TEditDto : IEntityDto<int>
       where TTranslationDto : TranslationDto
    {
        public MultiLingualCrudApplicationService(IRepository<TEntity> repository
           , IRepository<TEntityTranslation> translationRepository
           , string managerPermisson = null) : base(repository, translationRepository, managerPermisson) { }
    }
}

